﻿/**
* Copyright (c) 2021 Oray Inc. All rights reserverd.
*
* This document may not be reproduced, stored
* in a retrieval system, or transmitted, in any form, or by any means,
* electronic, mechanical, photocopying, recording, or otherwise,
* without the prior consent of Oray Inc.
*
*
* \file HighResTime.cpp
* \author panzhiyi
* \date 2021-4-23
* \brief 提供Windows下高精度时钟相关功能，其他平台请有需要的同事帮忙添加
*
*/
#include <memory.h>
#include "time/HighResTime.h"
#include "xsleep.h"
#ifdef _WIN32
#include <emmintrin.h>
#endif

CHighResTimer::CHighResTimer()
: m_nTimeMs(0)
{
#ifdef _WIN32
    QueryPerformanceFrequency(&m_liFrequency);
    QueryPerformanceCounter(&m_liStartCount);
#else
    memset(&m_tmStart, 0, sizeof(m_tmStart));
    gettimeofday(&m_tmStart, nullptr);
#endif
}

CHighResTimer::~CHighResTimer()
{

}

void CHighResTimer::Start()
{
#ifdef _WIN32
    QueryPerformanceCounter(&m_liStartCount);
#else
    memset(&m_tmStart, 0, sizeof(m_tmStart));
    gettimeofday(&m_tmStart, nullptr);
#endif
}

unsigned int CHighResTimer::Stop()
{
#ifdef _WIN32
    LARGE_INTEGER end = { 0 };
    QueryPerformanceCounter(&end);

    end.QuadPart = end.QuadPart - m_liStartCount.QuadPart;

    m_nTimeMs = (unsigned int) ((double) end.QuadPart * 1000 / m_liFrequency.QuadPart);
#else
    timeval tmNow = { 0 };
    gettimeofday(&tmNow, nullptr);

    m_nTimeMs = (unsigned int) difftimeval(&m_tmStart, &tmNow);
#endif

    return m_nTimeMs;
}

unsigned int CHighResTimer::GetValue()
{
    return m_nTimeMs;
}



CSystemTimeResModifier::CSystemTimeResModifier(unsigned int nPeriodInMs)
: m_nPeriodInMs(nPeriodInMs)
{
#ifdef _WIN32
    while(timeBeginPeriod(m_nPeriodInMs) == TIMERR_NOCANDO)
    {
        ++m_nPeriodInMs;
    }
#endif
}

CSystemTimeResModifier::~CSystemTimeResModifier()
{
#ifdef _WIN32
    timeEndPeriod(m_nPeriodInMs);
#endif
}

extern void HighResSleep(unsigned int milliseconds)
{
#ifdef _WIN32
    if(milliseconds <= 15)
    {
        CHighResTimer t;
        while(true)
        {
            if(t.Stop() >= milliseconds)
            {
                break;
            }
            _mm_pause();
        }
    }
    else
    {
        Sleep(milliseconds);
    }
#else
    Sleep(milliseconds);
#endif
}
